package taxicall.server; 

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.taxicall.entities.NetworkMessage;
import com.taxicall.entities.Taxi;
import com.taxicall.udptransport.SerializationUtils;
import com.taxicall.udptransport.UdpNetworkService;



public class Server {
	public final static int PORT = 4000;
	public final static int BUFFER_SIZE = 4096;
	
	private ServerController serverController;
	private ExecutorService threadPool;
	private UdpNetworkService network;
	
	Server(ServerController serverController, ExecutorService threadPool, UdpNetworkService network) {
		this.serverController = serverController;
		this.threadPool = threadPool;
		this.network = network;
	}
	
	public void listen() throws IOException {
		while (true) {
			final DatagramPacket inPacket = network.receive();

			if (inPacket == null)
				return;

			// process message in a seperate thread
			threadPool.execute(new Runnable() {
				@Override
				public void run() {
					NetworkMessage msg = (NetworkMessage) SerializationUtils
							.deserialize(inPacket.getData());
					try {
						callControllerAction(msg, inPacket.getAddress());
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
		}
	}
	
	// Call the controller action that corresponds to the message's type
	private void callControllerAction(NetworkMessage msg, InetAddress fromAddress) throws IOException {
		switch (msg.getType()) {

		case GetStartLocations:
			serverController.getStartLocations(fromAddress);
			break;
		case GetAllTaxis:
			serverController.getAvailableTaxis(fromAddress);
			break;
		case UpdateTaxi:
			serverController.updateTaxi((Taxi)msg.getDataObject(), fromAddress);
			break;
		default:
			System.out.println("Invalid message type: " + msg.getType());
		}
	}
	
	public static void main(String[] args) {
		
		// initialize network service
		UdpNetworkService network = null;
		try {
			network = new UdpNetworkService(Server.PORT, Server.BUFFER_SIZE);
		} catch (SocketException e) {
			e.printStackTrace();
			return;
		}
		
		// create the server controller and the executor service which will manage threading
		ServerController serverController = new ServerController(network);
		ExecutorService threadPool = Executors.newCachedThreadPool();

		// create and run the server
		Server server = new Server(serverController, threadPool, network);

		try {
			server.listen();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			network.close();
		}
		
	}
}
